package com.hzit.hzb.core.service.impl;


import cn.hutool.core.lang.hash.Hash;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hzit.common.exception.Assert;
import com.hzit.common.exception.BusinessException;
import com.hzit.common.result.ResponseEnum;
import com.hzit.hzb.core.enums.LendStatusEnum;
import com.hzit.hzb.core.enums.TransTypeEnum;
import com.hzit.hzb.core.hfb.FormHelper;
import com.hzit.hzb.core.hfb.HfbConst;
import com.hzit.hzb.core.hfb.RequestHelper;
import com.hzit.hzb.core.mapper.UserAccountMapper;
import com.hzit.hzb.core.pojo.entity.*;
import com.hzit.hzb.core.mapper.LendReturnMapper;
import com.hzit.hzb.core.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzit.hzb.core.util.LendNoUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.text.resources.cldr.en.FormatData_en_HK;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 还款记录表 服务实现类
 * </p>
 *
 * @author hbxfwf
 * @since 2024-08-27
 */
@Service
@Slf4j
public class LendReturnServiceImpl extends ServiceImpl<LendReturnMapper, LendReturn> implements LendReturnService {
	@Autowired
	private LendService lendService;
	@Autowired
	private UserInfoService userInfoService;
	@Autowired
	private LendItemReturnService lendItemReturnService;
	@Autowired
	private LendItemService lendItemService;
	@Autowired
	private TransFlowService transFlowService;
	@Autowired
	private LendReturnService lendReturnService;
	@Autowired
	private UserAccountMapper userAccountMapper;
	@Autowired
	private UserAccountService userAccountService;

	/**
	 * 根据标的id查询还款记录列表
	 * @param id
	 * @return
	 */
	@Override
	public List<LendReturn> fetchLendReturnList(Long id) {
		return this.list(new QueryWrapper<LendReturn>().eq("lend_id",id));
	}

	/**
	 * 借款人还款-->生成还款表单
	 * @param lendReturnId
	 * @param userId
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String commitReturn(Long lendReturnId, Long userId) {

		// 0. 根据还款记录号查询还款记录对象
		LendReturn lendReturn = this.getById(lendReturnId);
		Long lendId = lendReturn.getLendId();       // 标的id
		Lend lend = lendService.getById(lendId);    // 标的对象
		UserInfo userInfo = userInfoService.getById(userId);

		if(lend.getUserId().longValue() != userId.longValue()){
			throw new BusinessException("必须是同一借款人才能还款！");
		}

		//账户余额
		BigDecimal account = userAccountService.getAccount(userId);
		Assert.isTrue(account.doubleValue() >= lendReturn.getTotal().doubleValue(), ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);
		// 1. 定义表单参数
		Map<String, Object> paramMap = new HashMap<>();
		// 2. 存放表单参数
		paramMap.put("agentId",HfbConst.AGENT_ID);      // 商户id
		paramMap.put("agentGoodsName",lend.getTitle()); // 商户名称
		paramMap.put("agentBatchNo",lendReturn.getReturnNo());      // 批次号
		paramMap.put("fromBindCode",userInfo.getBindCode());        // 绑定协议号
		paramMap.put("totalAmt",lendReturn.getTotal());     // 还款总额
		paramMap.put("note","还款");
		List<Map<String,Object>> dataMap = findLendReturnItemListByLendReturnId(lendReturnId);
		paramMap.put("data", JSONUtil.toJsonStr(dataMap));
		paramMap.put("voteFeeAmt",new BigDecimal(0));       // 手续费
		paramMap.put("returnUrl",HfbConst.BORROW_RETURN_RETURN_URL);    // 同步回调
		paramMap.put("notifyUrl",HfbConst.BORROW_RETURN_NOTIFY_URL);    // 异步回调
		paramMap.put("timestamp", RequestHelper.getTimestamp());
		String sign = RequestHelper.getSign(paramMap);
		paramMap.put("sign",sign);
		return FormHelper.buildForm(HfbConst.BORROW_RETURN_URL,paramMap);
	}

	private List<Map<String, Object>> findLendReturnItemListByLendReturnId(Long lendReturnId) {
		// 1. 查询LendReturn对象
		LendReturn lendReturn = this.getById(lendReturnId);
		Long lendId = lendReturn.getLendId();
		Lend lend = lendService.getById(lendId);
		Long userId = lend.getUserId();
		UserInfo userInfo = userInfoService.getById(userId);
		// 2. 根据lendRuturnId查询出LendReturnItem列表
		List<LendItemReturn> lendItemReturnList = lendItemReturnService.list(new QueryWrapper<LendItemReturn>().eq("lend_return_id", lendReturnId));
		List<Map<String, Object>> lendItemReturnListMap = new ArrayList<>();
		// 3. 重新将lendItemReturnList集合中的数据放到lendItemReturnListMap集合中
		for (LendItemReturn lendItemReturn : lendItemReturnList) {
			Long lendItemId = lendItemReturn.getLendItemId();
			LendItem lendItem = lendItemService.getById(lendItemId);
			Map<String, Object> map = new HashMap<>();
			map.put("agentProjectCode",lend.getLendNo());       // 还款项目编号
			map.put("voteBillNo",lendItem.getLendItemNo());     // 还款单号
			map.put("toBindCode",userInfo.getBindCode());
			map.put("transitAmt",lendItemReturn.getTotal());    // 还款金额
			map.put("baseAmt",lendItemReturn.getPrincipal());   // 还款本金
			map.put("benifitAmt",lendItemReturn.getInterest()); // 还款利息
			map.put("feeAmt",new BigDecimal(0)); // 手续费
			lendItemReturnListMap.add(map);
		}
		return lendItemReturnListMap;
	}

	/**
	 * 借款人还款的异步回调
	 * @param paramMap
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String notifyUrl(Map<String, Object> paramMap) {
		String agentBatchNo = paramMap.get("agentBatchNo").toString();
		TransFlow transFlow = transFlowService.getOne(new QueryWrapper<TransFlow>().eq("trans_no", agentBatchNo));
		if(transFlow != null){
			log.info("幂等性返回!");
			return "success";
		}
		// 1. 查询还款对象并修改
		LendReturn lendReturn = lendReturnService.getOne(new QueryWrapper<LendReturn>().eq("return_no", agentBatchNo));
		lendReturn.setStatus(1);    // 己归还
		lendReturn.setFee(new BigDecimal((String)paramMap.get("voteFeeAmt")));  // 手续费
		lendReturn.setRealReturnTime(LocalDateTime.now());                      // 实际还款时间
		lendReturnService.updateById(lendReturn);                               // 修改还款对象

		// 2. 如果是最后一次还款，就修改标的状态为”己还清“
		Lend lend = lendService.getById(lendReturn.getLendId());
		if (lendReturn.getLast()) {

			lend.setStatus(LendStatusEnum.PAY_OK.getStatus());
			lendService.updateById(lend);
		}

		Long userId = lendReturn.getUserId();
		UserInfo userInfo = userInfoService.getById(userId);
		// 3. 借款账户转出
		BigDecimal totalAmt = new BigDecimal((String)paramMap.get("totalAmt"));
		userAccountMapper.updateUserAccount(totalAmt.negate(),userInfo.getBindCode(),new BigDecimal(0));
		// 4. 向交易流水表添加还款记录信息
		transFlow = new TransFlow();
		transFlow.setUserName(userInfo.getName());
		transFlow.setUserId(userInfo.getId());
		transFlow.setTransType(TransTypeEnum.RETURN_DOWN.getTransType());
		transFlow.setTransTypeName(TransTypeEnum.RETURN_DOWN.getTransTypeName());
		transFlow.setTransAmount(totalAmt);
		transFlow.setTransNo(LendNoUtils.getReturnItemNo());
		transFlow.setMemo( "借款人还款扣减，项目编号：" + lend.getLendNo() + "，项目名称：" + lend.getTitle());
		transFlowService.save(transFlow);

		// 5. 修改回款明细
		List<LendItemReturn> lendItemReturnList = lendItemReturnService.list(new QueryWrapper<LendItemReturn>().eq("lend_return_id", lendReturn.getId()));
		for (LendItemReturn itemReturn : lendItemReturnList) {
			// 5.1 更新lendItemReturn (回款计划表)
			itemReturn.setStatus(1);        // 己归还
			itemReturn.setRealReturnTime(LocalDateTime.now());
			lendItemReturnService.updateById(itemReturn);
			// 5.2 更新标的项信息
			Long lendItemId = itemReturn.getLendItemId();
			LendItem lendItem = lendItemService.getById(lendItemId);
			lendItem.setRealAmount(itemReturn.getInterest());   // 设置实际收益
			lendItemService.updateById(lendItem);
			//5.3 投资账号转入金额
			userInfo = userInfoService.getById(itemReturn.getInvestUserId());
			userAccountMapper.updateUserAccount(lendReturn.getTotal(),userInfo.getBindCode(),new BigDecimal(0));
			// 5.4 添加交易流水记录
			transFlow = new TransFlow();
			transFlow.setMemo("还款到账，项目编号：" + lend.getLendNo() + "，项目名称：" + lend.getTitle());
			transFlow.setTransAmount(itemReturn.getTotal());
			transFlow.setTransTypeName(TransTypeEnum.INVEST_BACK.getTransTypeName());
			transFlow.setTransType(TransTypeEnum.INVEST_BACK.getTransType());
			transFlow.setUserName(userInfo.getName());
			transFlow.setTransNo(LendNoUtils.getReturnItemNo());
			transFlow.setUserId(itemReturn.getInvestUserId());
			transFlowService.save(transFlow);
		}
		return "success";
	}
}
